package pure.engine.world 
{
	import flash.geom.*;
	import pure.debug.Logger;
	import pure.engine.core.IFrameListener;
	import pure.engine.core.ns_despair;
	import pure.engine.core.ProcessManager;
	import pure.engine.core.SystemManager;
	import pure.engine.model.Entity;
	import pure.engine.model.EntityManager;
	import pure.engine.model.Model2D;
	import pure.engine.events.InteractEvent;
	import pure.engine.world.decorator.MouseMonitor;
	import pure.engine.model.Renderer;
	import pure.utils.DesU;
	import flash.events.EventDispatcher;
	import pure.engine.core.ns_despair;
	use namespace ns_despair;
	
	/**
	 * 世界主体
	 * [Author] - PURE
	 * 
	 * [Hint] - 世界的载体，对其封装，管理与更新世界.
	 */
public class WorldBody implements IFrameListener
{
	public function WorldBody(name:String, regionSize:int, viewW:int, viewH:int, numExtendedRegion:int, optimized:Boolean)
	{
		this.m_name     =  name;
		this.m_viewW    =  viewW;
		this.m_viewH    =  viewH;
		m_regionFusion  =  new RegionFusion(regionSize, numExtendedRegion);
		this.m_flags    =  optimized ? (w_readyFlag | w_optimizeFlag | w_interactiveFlag) : (w_readyFlag | w_interactiveFlag);
		
		ProcessManager.instance.addFrameListener(this, ProcessManager.WORLD);
	}
	
	
	
	//======================
	// Const
	//======================
	
	
	ns_despair static const w_readyFlag:uint        =  0x01;  //  准备完毕
	ns_despair static const w_advanceFlag:uint      =  0x02;  //  更新
	ns_despair static const w_enterFlag:uint        =  0x04;  //  进入新世界
	
	ns_despair static const w_optimizeFlag:uint     =  0x10;  //  是否优化
	ns_despair static const w_interactiveFlag:uint  =  0x20;  //  是否交互
	
	
	
	//======================
	// Property
	//======================
	
	
	/**
	 * 是否可交互
	 */
	public function get interactive():Boolean
	{
		return Boolean(m_flags & w_interactiveFlag);
	}
	
	public function set interactive(b:Boolean):void
	{
		if (b)
		{
			m_flags |= w_interactiveFlag;
		}
		else
		{
			m_flags &= ~w_interactiveFlag;
		}
	}
	
	
	
	
	/**
	 * 获取监视器
	 */
	public function getMonitor():IMonitor
	{
		return WorldManager.m_monitorList[m_name];
	}
	
	
	/**
	 * 设置世界
	 * 
	 * [Param] - world  世界
	 * 
	 * [Feature] -     WorldBody       Monitor
	 * 
	 *            1.     Ready         Exiting
	 *            2.     Advance       Modified
	 *            3.     Enter   
	 */
	public function setWorld(world:World):void 
	{
		if (Boolean(m_flags & w_advanceFlag))
		{
			WorldManager.exitWorld(this.m_name);
			m_flags &= ~w_advanceFlag;
			
			Logger.reportMessage(this, 'Exit the current world : ' + DesU.getClassName(m_world));
		}
		if (world)
		{
			m_flags |= w_enterFlag;
		}
		else
		{
			m_flags &= ~w_enterFlag;
		}
		m_world = world;
	}

	
	/**
	 * 更新
	 */
	public function update(deltaTime:Number):void
	{
		if (Boolean(m_flags & w_advanceFlag))
		{
			updateAllModels();
			m_world.update();
		}
		
		// 新世界
		else if (Boolean(m_flags & w_readyFlag) && Boolean(m_flags & w_enterFlag))
		{
			WorldManager.enterWorld(this.m_name);
			m_flags = (m_flags & 0xF0) | w_advanceFlag;
			
			Logger.reportMessage(this,'Enter new world : ' + DesU.getClassName(m_world));
		}
	}
	
	
	/**
	 * 能否交互
	 */
	ns_despair function get canInteract():Boolean
	{
		return Boolean(m_flags & w_advanceFlag);
	}
	
	
	/**
	 * 进入世界
	 */
	ns_despair function enterWorld():void
	{
		this.m_regionFusion.setRegions(m_world.m_numRegionX, m_world.m_numRegionY, m_world.m_regionData);
		m_world.enter();
		cachedDownModelID = cachedOverModelID = cachedDownRendererIndex = cachedOverRendererIndex = -1;
	}
	
	
	/**
	 * 退出世界
	 */
	ns_despair function exitWorld():void
	{
		this.m_world.destroy();
		this.m_world.exit();
		this.m_regionFusion.clearRegions();
		this.m_dirtyModelList.length = this.m_dirtyModelLength = this.m_modifiedModelList.length = 0;
	}
	

	/**
	 * 完成退出
	 */
	ns_despair function finishExit():void
	{
		this.m_flags |= w_readyFlag;
	}

	
	/**
	 * 清理(全部模型)
	 */
	ns_despair function clear():void
	{
		this.m_regionFusion.removeAllModels();
		this.m_dirtyModelList.length = this.m_dirtyModelLength = this.m_modifiedModelList.length = 0;
	}
	
	
	/**
	 * 加入脏模型
	 * 
	 * [Param] - model  模型
	 */
	ns_despair function addDirtyModel(model:Model2D):void
	{
		m_dirtyModelList[m_dirtyModelLength++] = model;
	}

	
	/**
	 * 移除模型
	 * 
	 * [Param] - model  模型
	 * [Param] - dirty  脏的
	 */
	ns_despair function removeModel(model:Model2D, dirty:Boolean):void
	{
		// 脏模型
		if (dirty)
		{
			var index:int            =  m_dirtyModelList.indexOf(model);
			m_dirtyModelList[index]  =  m_dirtyModelList[--m_dirtyModelLength];
			m_dirtyModelList.pop();
		}
		
		// 从区块移除
		m_regionFusion.removeModel(model);
	}
	

	/**
	 * 更新模型
	 */
	ns_despair function updateAllModels():void
	{
		var RX:int, RY:int, grid:int, oldGrid:int, l:int = m_world.m_freshModelLength; 
		var freshList:Array = m_world.m_freshModelList;
		var model:Model2D;
		
		// 完全照亮
		if (!Boolean(m_flags & w_optimizeFlag))
		{
			// 新入模型
			while (--l > -1)
			{
				model = freshList[l]
				m_regionFusion.addModel(model);
				model.addToWorld(true);
				model.m_worldbody = this;
			}
			m_modifiedModelList.push.apply(null, freshList);
			
			// 脏模型
			l = m_dirtyModelLength;
			while (--l > -1)
			{
				model = m_dirtyModelList[l];
				m_regionFusion.moveModel(model);
				
				// 残像位置
				model.modify();
			}
		}
		
		// 部分照亮
		else
		{
			// 新入模型，渲染区以外不留残像
			while (--l > -1)
			{
				model  =  freshList[l];
				grid   =  m_regionFusion.addModel(model);
				RX     =  grid & 0xFF;
				RY     =  grid >> 8;
				if (RX > m_viewRegionLeft && RX < m_viewRegionRight || RY > m_viewRegionTop || RY < m_viewRegionBottom)
				{
					model.addToWorld(true);
					m_modifiedModelList.push(model);
				}
				else
				{
					model.addToWorld(false);
				}
				model.m_worldbody = this;
			}
			
			// 更新脏模型，调整区块，进入渲染区域以外的模型移除残像
			l = m_dirtyModelLength;
			while (--l > -1)
			{
				model = m_dirtyModelList[l];
				grid  =  m_regionFusion.moveModel(model);
				if (grid > -2)
				{
					RX    =  grid & 0xFF;
					RY    =  grid >> 8;
					
					// 移出渲染区域
					if (RX < m_viewRegionLeft || RX > m_viewRegionRight || RY < m_viewRegionTop || RY > m_viewRegionBottom)
					{
						model.setRenderEnabled(false);
					}
					// 进入渲染区域
					else
					{
						model.setRenderEnabled(true);
						m_modifiedModelList.push(model);
					}
				}
			}
		}
		m_dirtyModelList.length = m_dirtyModelLength = 0;
		m_world.reset();
	}
	
	
	/**
	 * 清除全部模型
	 */
	ns_despair function removeAllModels():void
	{
		m_regionFusion.removeAllModels();
		m_dirtyModelList.length = m_dirtyModelLength = 0;
	}

	
	/**
	 * 更新交互状态
	 * 
	 * [Param] - type    类型
	 * [Param] - worldX  世界坐标x
	 * [Param] - worldY  世界坐标y
	 */
	ns_despair function updateInteractedState(type:String, worldX:Number, worldY:Number):void
	{
		if (!Boolean(m_flags & w_interactiveFlag))
		{
			return;
		}
		
		var interactEvent:InteractEvent;
		var modelList:Array, fragmentList:Array;
		var model:Model2D, tmpModel:Model2D;
		var renderer:Renderer;
		var type:String;
		var i:int, l:int, ll:int, numRenderer:int, currID:int, currIndex:int;
		var fragment:Fragment;
		
		modelList = m_regionFusion.getAllModelByPoint(worldX, worldY);
		l = ll = modelList.length;
		for (i = 0; i < l; i++)
		{
			if (!modelList[i].m_interactive)
			{
				modelList[i--] = modelList[--l];
			}
		}
		if (ll - l > 0)
		{
			modelList.splice(l, ll - l);
		}
		modelList.sortOn(m_sortProperty, Array.NUMERIC);
		
		while (--l > -1)
		{
			model        =  modelList[l];
			numRenderer  =  model.m_numRenderer;
			
			// 渲染器
			while(--numRenderer > -1)
			{
				renderer = model.m_rendererList[numRenderer];
				
				// 可交互渲染器
				if (renderer.m_interactive && renderer.m_fragment.getMousePixel() > 0)
				{
					// 【按下】
					if (type == 'mouseDown')
					{
						// 【Press】
						cachedDownModelID        =  model.m_id;
						cachedDownRendererIndex  =  numRenderer;
						
						// Model
						model.dispatchEvent(interactEvent = new InteractEvent(InteractEvent.PRESS, worldX, worldY));
						
						// Renderer
						if (interactEvent.prevented)
						{
							modelList.length = 0;
							return;
						}
						else if (renderer.interactive)
						{
							renderer.dispatchEvent(interactEvent = new InteractEvent(InteractEvent.PRESS, worldX, worldY));
						}
						
						// World
						if (!interactEvent.prevented)
						{
							m_world.dispatchEvent(interactEvent = new InteractEvent(InteractEvent.PRESS, worldX, worldY));
						}
						
						modelList.length = 0;
						return;
					}
					
					// 【释放】
					else if (type == 'mouseUp')
					{	
						currID     =  model.m_id;
						currIndex  =  numRenderer;
						
						// 【Click】
						if (cachedDownModelID == currID)
						{
							// Model
							model.dispatchEvent(interactEvent = new InteractEvent(InteractEvent.CLICK, worldX, worldY));
							
							// Renderer
							if (cachedDownRendererIndex == currIndex && renderer.interactive && !interactEvent.prevented)
							{
								renderer.dispatchEvent(interactEvent = new InteractEvent(InteractEvent.CLICK, worldX, worldY));
							}
							
							// World
							if (!interactEvent.prevented)
							{
								m_world.dispatchEvent(interactEvent = new InteractEvent(InteractEvent.CLICK, worldX, worldY));
							}
						}
						
						// 【Release】
						cachedDownModelID = cachedDownRendererIndex = -1;
						
						// Model
						model.dispatchEvent(interactEvent = new InteractEvent(InteractEvent.RELEASE, worldX, worldY));
						
						// Renderer
						if (interactEvent.prevented)
						{
							modelList.length = 0;
							return;
						}
						else if (renderer.interactive)
						{
							renderer.dispatchEvent(interactEvent = new InteractEvent(InteractEvent.RELEASE, worldX, worldY));
						}
						
						// World
						if (!interactEvent.prevented)
						{
							m_world.dispatchEvent(interactEvent = new InteractEvent(InteractEvent.RELEASE, worldX, worldY));
						}
						
						modelList.length = 0;
						return;
					}
					
					// 【移动】
					else if (type == 'mouseMove')
					{
						currID     =  model.m_id;
						currIndex  =  numRenderer;
						tmpModel   =  Model2D.getModelByID(cachedOverModelID);
						
						// Model
						if (cachedOverModelID != currID)
						{
							// 【LEAVE】
							if (tmpModel != null)
							{
								// Model
								tmpModel.dispatchEvent(new InteractEvent(InteractEvent.LEAVE, worldX, worldY));
								
								// Renderer
								tmpModel.getRendererAt(cachedOverRendererIndex).dispatchEvent(new InteractEvent(InteractEvent.LEAVE, worldX, worldY));
							}
							
							// 【OVER】
							model.getRendererAt(numRenderer).dispatchEvent(new InteractEvent(InteractEvent.OVER, worldX, worldY));
								
							// 【OVER】
							model.dispatchEvent(new InteractEvent(InteractEvent.OVER, worldX, worldY));
							
							cachedOverModelID        =  currID;
							cachedOverRendererIndex  =  numRenderer;
						}
						
						else
						{
							// 【Move】
							model.dispatchEvent(new InteractEvent(InteractEvent.MOVE, worldX, worldY));
							
							// Renderer
							if (numRenderer != cachedOverRendererIndex)
							{
								// 【LEAVE】
								tmpModel.getRendererAt(cachedOverRendererIndex).dispatchEvent(new InteractEvent(InteractEvent.LEAVE, worldX, worldY));
								
								// 【OVER】
								model.getRendererAt(numRenderer).dispatchEvent(new InteractEvent(InteractEvent.OVER, worldX, worldY));
								
								cachedOverRendererIndex = numRenderer;
							}
							else
							{
								// 【Move】
								model.getRendererAt(numRenderer).dispatchEvent(new InteractEvent(InteractEvent.MOVE, worldX, worldY));
							}
						}
						
						// World 【Move】
						m_world.dispatchEvent(new InteractEvent(InteractEvent.MOVE, worldX, worldY));
						
						modelList.length = 0;
						return;
					}
				}
			}
		}
		
		// 【LEAVE】
		if (cachedOverModelID > 0)
		{
			tmpModel = Model2D.getModelByID(cachedOverModelID);
			if (tmpModel != null)
			{
				// Model
				tmpModel.dispatchEvent(new InteractEvent(InteractEvent.LEAVE, worldX, worldY));
				
				// Renderer
				tmpModel.getRendererAt(cachedOverRendererIndex).dispatchEvent(new InteractEvent(InteractEvent.LEAVE, worldX, worldY));
			}
			
			cachedOverModelID = cachedOverRendererIndex = -1;
		}
		
		// World(空白处)
		m_world.dispatchEvent(new InteractEvent(InteractEvent.MOVE, worldX, worldY));
		modelList.length = 0;
	}
	

	/**
	 * 控制视域在世界范围
	 */
	ns_despair function clampInWorld():void 
	{
	}
	
	
	
	
	//======================
	// Member
	//======================

	
	ns_despair static var m_sortProperty:Array;
	
	
	ns_despair var m_world:World;  // 装载的世界

	ns_despair var m_name:String;  // 主体名字
	
	ns_despair var m_flags:int;  // 状态

	ns_despair var m_regionFusion:RegionFusion;

	ns_despair var m_dirtyModelList:Vector.<Model2D> = new Vector.<Model2D>();  // 脏模型列表

	ns_despair var m_dirtyModelLength:int;  // 脏模型数量

	ns_despair var m_modifiedModelList:Array;  // 发生残像的新入模型列表，残像深度排序

	
	//ns_despair var m_numExtendedRegion:int;  // 延伸区块数量
	//
	//ns_despair var m_regionSize:int;  // 区块大小
	//
	//ns_despair var m_numRegionX:int, m_numRegionY:int;  // 总区块数量
	//
	ns_despair var m_viewX:Number, m_viewY:Number;  // 视域坐标
	
	ns_despair var m_viewW:int, m_viewH:int;  // 视域大小
	
	ns_despair var m_viewRegionTop:int, m_viewRegionBottom:int, m_viewRegionLeft:int, m_viewRegionRight:int;  // 视域所占区块

	ns_despair var cachedDownModelID:int;  // 缓存按下的模型id
	
	ns_despair var cachedDownRendererIndex:int;  // 缓存按下的渲染器索引
	
	ns_despair var cachedOverModelID:int;  // 缓存移上的模型id
		
	ns_despair var cachedOverRendererIndex:int;  // 缓存移上的渲染器索引
	
	ns_despair var cachedPressed:Boolean;  // 是否按下
	
}

}